package org.chen.common.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.apache.shardingsphere.api.config.masterslave.LoadBalanceStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.shardingsphere.api.config.masterslave.MasterSlaveRuleConfiguration;

import java.util.*;

@Configuration
public class DruidConfig {

    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "cfx2000..");
        servletRegistrationBean.addInitParameter("resetEnable", "true");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.html,*.png,*.ico,*.js,*.gif,*.jpg,*.css,/druid/*");
        return filterRegistrationBean;
    }

    @Bean
    @ConfigurationProperties("spring.shardingsphere.datasource.ds0")
    public DataSource ds0() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.shardingsphere.datasource.ds1")
    public DataSource ds1() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.shardingsphere.datasource.ds0slave0")
    public DataSource ds0slave0() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.shardingsphere.datasource.ds1slave0")
    public DataSource ds1slave0() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "customShardingDataSource")
    public DataSource shardingDataSource() throws SQLException {
        // 配置数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        dataSourceMap.put("ds0", ds0());
        dataSourceMap.put("ds1", ds1());
        dataSourceMap.put("ds0slave0", ds0slave0());
        dataSourceMap.put("ds1slave0", ds1slave0());

        // 配置分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();

        // 配置订单表分片规则
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("fy_store_travel_order", "ds${0..1}.fy_store_travel_order");
        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "ds${id % 2}"));
        shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);

        // 配置订单信息表分片规则
        TableRuleConfiguration infoTableRuleConfig = new TableRuleConfiguration("fy_store_order_travel_info", "ds${0..1}.fy_store_order_travel_info");
        infoTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "ds${order_id % 2}"));
        shardingRuleConfig.getTableRuleConfigs().add(infoTableRuleConfig);

        // 配置订单状态表分片规则
        TableRuleConfiguration statusTableRuleConfig = new TableRuleConfiguration("fy_store_order_status", "ds${0..1}.fy_store_order_status");
        statusTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("oid", "ds${oid % 2}"));
        shardingRuleConfig.getTableRuleConfigs().add(statusTableRuleConfig);

        // 添加每日统计表的分片配置
        TableRuleConfiguration statsTableRuleConfig = new TableRuleConfiguration(
                "fy_daily_stats",
                "ds${0..1}.fy_daily_stats"
        );
        // 使用stat_date的日期来分片，比如奇数日期到ds0，偶数日期到ds1
        statsTableRuleConfig.setDatabaseShardingStrategyConfig(
                new StandardShardingStrategyConfiguration(
                        "stat_date",  // 分片键
                        (PreciseShardingAlgorithm<Date>) (availableTargetNames, shardingValue) -> {
                            Calendar cal = Calendar.getInstance();
                            cal.setTime(shardingValue.getValue());
                            int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
                            return "ds" + (dayOfMonth % 2);
                        }
                )
        );

        shardingRuleConfig.getTableRuleConfigs().add(statsTableRuleConfig);

        // 配置绑定表
        shardingRuleConfig.getBindingTableGroups().add("fy_store_travel_order,fy_store_order_travel_info,fy_store_order_status");

        // 配置读写分离规则
        List<MasterSlaveRuleConfiguration> masterSlaveRuleConfigs = new ArrayList<>();

        // ds0的主从配置
        masterSlaveRuleConfigs.add(new MasterSlaveRuleConfiguration(
                "ds0",
                "ds0",
                Collections.singletonList("ds0slave0"),
                new LoadBalanceStrategyConfiguration("ROUND_ROBIN")
        ));

        // ds1的主从配置
        masterSlaveRuleConfigs.add(new MasterSlaveRuleConfiguration(
                "ds1",
                "ds1",
                Collections.singletonList("ds1slave0"),
                new LoadBalanceStrategyConfiguration("ROUND_ROBIN")
        ));

        shardingRuleConfig.setMasterSlaveRuleConfigs(masterSlaveRuleConfigs);

        // 配置属性
        Properties props = new Properties();
        props.put("sql.show", true);
        props.put("executor.size", 2);
        props.put("max.connections.size.per.query", 1);

        return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, props);
    }
}
